package socket

//处理socket服务器端

import (
	"got/cache"
	"net"
	"time"
)

//tcp服务器
type Server struct {
	onConnect   ServerConnectHandleFunc //当连接的时候触发的回调
	onMessage   MessageHandleFunc       //消息来时
	onHeartbeat MessageHandleFunc       //心跳数据
	onClose     DefHandleFunc           //当关闭连接时触发的回调
	onError     ErrorHandleFunc         //当发生错误时触发的回调
	connPool    *cache.Cache            //连接池
	heartbeat   []byte                  //心跳数据
	size        int                     //最大连接数
}

//创建一个server,并初始化连接池
func NewServer(size int) *Server {
	obj := new(Server)
	obj.connPool = cache.NewCache(size) //设置memery的初始内存大小，同时也作为连接池的数量控制
	obj.size = size                     //
	return obj
}

//设置心跳数据内容（如果服务器收到该数据会忽略掉,并直接返回给客户端)
func (this *Server) SetHeartbeat(bt []byte) {
	this.heartbeat = bt
}

//注册当socket连接时回调,返回一个连接编号
func (this *Server) OnConnect(call ServerConnectHandleFunc) {
	this.onConnect = call
}

//注册当socket接收到消息时的回调
func (this *Server) OnMessage(call MessageHandleFunc) {
	this.onMessage = call
}

//注册心跳数据处理的回调
func (this *Server) OnHeartbeat(call MessageHandleFunc) {
	this.onHeartbeat = call
}

//注册当socket关闭连接时的回调
func (this *Server) OnClose(call DefHandleFunc) {
	this.onClose = call
}

//注册当socket发生错误时的回调
func (this *Server) OnError(call ErrorHandleFunc) {
	this.onError = call
}

//通过连接编号获取某个连接对象
func (this *Server) GetConn(id string) (conn *Conn) {
	if c := this.connPool.Get(id); c != nil {
		conn = c.(*Conn)
	}
	return
}

//遍历所有连接对象
func (this *Server) EachConn(call func(c *Conn)) {
	this.connPool.Each(func(id, conn interface{}) {
		if c, ok := conn.(*Conn); ok {
			call(c)
		}
	})
}

//检查距离上次链接时间是否超过tm，如果超过则执行call回调
//tm单位=秒
func (this *Server) CheckTimeout(tm int64, call func(c *Conn)) {
	now := time.Now().Unix()
	this.connPool.Each(func(id, conn interface{}) {
		if c, ok := conn.(*Conn); ok && now-c.LastAccessTime.Unix() > tm {
			call(c)
		}
	})
}

//发起监听
func (this *Server) Listen(laddr string) error {
	listener, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}
	for {
		//等待客户端接入
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		go try(func() {
			this.handleConnect(conn)
		}, func(e Error) {
			this.onError(nil, e)
		})
	}
	return nil
}

//处理每个连接
func (this *Server) handleConnect(c net.Conn) {
	//创建连接
	conn := newConn(c)
	conn.id = this.makeConnId() //使用连接池长度作为地址编号
	defer func() {
		ifcall(this.onClose != nil, func() {
			this.onClose(conn)
		})
		conn.Close()               //保证正常关闭连接
		this.connPool.Del(conn.id) //删除连接池的数据
	}()
	headData, err := conn.Read() //初次连接发送的头数据
	if err != nil {
		ifcall(this.onError != nil, func() {
			this.onError(conn, err)
		})
		return
	}
	conn.LastAccessTime = time.Now()           //最后访问时间
	conn.Write(this.onConnect(conn, headData)) //客户端连接成后立即返回数据
	this.connPool.Set(conn.id, conn)           //保存连接到连接池
	for {
		readData, err := conn.Read()
		if err != nil {
			break
		}
		//循环体内保证不抛出异常
		go try(func() {
			conn.Lock()                      //加锁保证执行顺序
			defer conn.Unlock()              //
			conn.LastAccessTime = time.Now() //更新链接时间
			//如果是心跳数据
			if len(readData) == len(this.heartbeat) && string(readData) == string(this.heartbeat) {
				ifcall(this.onHeartbeat != nil, func() {
					this.onHeartbeat(conn, readData)
				})
				conn.Write(this.heartbeat)
			} else { //否则是普通数据
				ifcall(this.onMessage != nil, func() {
					this.onMessage(conn, readData) //消息处理
				})
			}
		}, func(e Error) {
			ifcall(this.onError != nil, func() {
				this.onError(conn, err)
			})
		})
	}
}

//创建连接编号
func (this *Server) makeConnId() int64 {
	return time.Now().Unix() + int64(this.connPool.Len())
}

//检查错误
func (this *Server) checkError(err error) int {
	if err != nil {
		if err.Error() == "EOF" {
			return 0
		}
		return -1
	}
	return 1
}
